﻿using System;
using System.IO;
using eWallet.Data.Local;
using eWallet.Data.Local.eWalletDataSetTableAdapters;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Security.Cryptography.X509Certificates;
using eWallet.Security.Cryptography;
using System.Data.SqlServerCe;
using System.Collections.Generic;
using System.Transactions;

namespace eWallet.Tests
{
	/// <summary>
	/// Tests that access data in the database using the table adapters.
	/// </summary>
	[TestClass]
	public class DataAccessTests
	{

		private string ConnectionString
		{
			get { return string.Format(@"Data Source=""{0}""", this.DatabasePath); }
		}

		private string DatabasePath { get; set; }

		[TestInitialize]
		public void TestInitialize()
		{
			this.DatabasePath = string.Format(@"{0}\{1}.sdf", Environment.GetEnvironmentVariable("TEMP"), Guid.NewGuid());
			eWalletDataSet.CreateEmptyDatabase(this.DatabasePath);
		}

		[TestCleanup]
		public void TestCleanup()
		{
			if (File.Exists(this.DatabasePath))
				File.Delete(this.DatabasePath);

			this.DatabasePath = null;
		}



		#region Test: public void AddSecretTag01()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void AddSecretTag01()
		{
			Guid groupId, secretId;
			PasswordCryptoModule module = new PasswordCryptoModule("1234");
			using (eWalletDataSet ds = new eWalletDataSet())
			{
				using (TableAdapterManager tam = new TableAdapterManager(this.DatabasePath))
				{
					var groupRow = ds.Groups.AddGroupsRow("Default", null, module);
					groupId = groupRow.Id;

					tam.BlobsTableAdapter.Update(ds.Blobs);
					tam.GroupsTableAdapter.Update(ds.Groups);

					var secretRow = ds.Secrets.AddSecretsRow(null, "secret data", ds.Groups[0], module);
					secretId = secretRow.Id;

					tam.BlobsTableAdapter.Update(ds.Blobs);
					tam.SecretsTableAdapter.Update(ds.Secrets);
					tam.SecretsTableAdapter.SetTags(secretId, "Tag 2", "Tag 1");

					tam.SecretsTableAdapter.Fill(ds.Secrets);
					tam.TagsTableAdapter.Fill(ds.Tags);
					tam.SecretsTagsTableAdapter.Fill(ds.SecretsTags);

					Assert.AreEqual<int>(1, ds.Secrets.Count);
					Assert.AreEqual<int>(2, ds.Tags.Count);
					Assert.AreEqual<int>(2, ds.SecretsTags.Count);

					var arr = ds.Secrets[0].GetSecretsTagsRows();
					var tags = new List<string>(ds.Secrets[0].GetTags());
					Assert.AreEqual<int>(2, tags.Count);
					Assert.AreEqual<string>("Tag 1", tags[0]);
					Assert.AreEqual<string>("Tag 2", tags[1]);

				}
			}

		}

		#endregion

		#region Test: public void AddSecretTag02()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute("Adds tags to a secret that does not exist and expects no error.")]
		public void AddSecretTag02()
		{
			using (SecretsTableAdapter adr = new SecretsTableAdapter(this.DatabasePath))
			{
				adr.SetTags(Guid.NewGuid(), "Tag 1", "Tag 2");
			}
		}

		#endregion



		#region Test: public void CreateGroup01()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void CreateGroup01()
		{
			Guid id;
			using (eWalletDataSet ds = new eWalletDataSet())
			{
				var row = ds.Groups.AddGroupsRow("1st Key", "This is the first key", new PasswordCryptoModule("qwerty"));
				id = row.Id;
				using(BlobsTableAdapter adr = new BlobsTableAdapter(this.DatabasePath))
				{
					adr.Update(ds.Blobs);
				}
				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					int i = adr.Update(ds.Groups);
					Assert.AreEqual<int>(1, i);
				}
			}

			using (eWalletDataSet ds = new eWalletDataSet())
			{
				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					int i = adr.Fill(ds.Groups);
					Assert.AreEqual<int>(1, i);
				}

				Assert.AreEqual<int>(1, ds.Groups.Count);
				Assert.AreEqual<Guid>(id, ds.Groups[0].Id);
				Assert.AreEqual<EncryptionMethod>(EncryptionMethod.Password, ds.Groups[0].EncryptionMethod);
			}
		}

		#endregion

		#region Test: public void CreateGroup02()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void CreateGroup02()
		{
			Guid id;
			using (eWalletDataSet ds = new eWalletDataSet())
			{
				var row = ds.Groups.AddGroupsRow("My Name", "My Description", new CertificationCryptoModule(new X509Certificate2(Properties.Resources.eWalletTestCertificate1)));
				id = row.Id;

				using (BlobsTableAdapter adr = new BlobsTableAdapter(this.DatabasePath))
				{
					adr.Update(ds.Blobs);
				}
				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					int i = adr.Update(ds.Groups);
					Assert.AreEqual<int>(1, i);
				}
			}

			using (eWalletDataSet ds = new eWalletDataSet())
			{
				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					int i = adr.Fill(ds.Groups);
					Assert.AreEqual<int>(1, i);
				}

				Assert.AreEqual<int>(1, ds.Groups.Count);
				Assert.AreEqual<Guid>(id, ds.Groups[0].Id);
				Assert.AreEqual<EncryptionMethod>(EncryptionMethod.Certificate, ds.Groups[0].EncryptionMethod);
			}
		}

		#endregion



		#region Test: public void ReadBlob01()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void ReadBlob01()
		{
			using (TableAdapterManager tam = new TableAdapterManager(this.DatabasePath))
			{
				Guid blobId;

				using (eWalletDataSet ds = new eWalletDataSet())
				{
					ds.Blobs.AddBlobsRow(Guid.NewGuid(), new byte[1]);
					blobId = ds.Blobs[0].Id;
					tam.BlobsTableAdapter.Update(ds.Blobs);
				}

				using (eWalletDataSet ds = new eWalletDataSet())
				{
					int i = tam.BlobsTableAdapter.Fill(ds.Blobs, blobId);
					Assert.AreEqual<int>(1, i);
					Assert.AreEqual<int>(1, ds.Blobs.Count);
				}
			}
		}

		#endregion
		


		#region Test: public void ReadGroup01()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void ReadGroup01()
		{
			using (eWalletDataSet ds = new eWalletDataSet())
			{
				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					int i = adr.Fill(ds.Groups);
					Assert.AreEqual<int>(0, i);
				}

				Assert.AreEqual<int>(0, ds.Groups.Count);
			}
		}

		#endregion

		#region Test: public void ReadGroup02()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void ReadGroup02()
		{
			PasswordCryptoModule pwd = new PasswordCryptoModule("lkjlkjwijoiu");
			using (eWalletDataSet ds = new eWalletDataSet())
			{
				var key = ds.Groups.AddGroupsRow("Default", null, pwd);
				Guid id = key.Id;
				Assert.AreNotEqual<Guid>(Guid.Empty, id);

				using (BlobsTableAdapter adr = new BlobsTableAdapter(this.DatabasePath))
				{
					adr.Update(ds.Blobs);
				}

				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					int i = adr.Update(ds.Groups);
					Assert.AreEqual<int>(1, i);

					ds.Groups.Clear();
					Assert.AreEqual<int>(0, ds.Groups.Count);

					i = adr.Fill(ds.Groups, id);
					Assert.AreEqual<int>(1, i);
					Assert.AreEqual<Guid>(id, ds.Groups[0].Id);
				}
			}
		}

		#endregion

		#region Test: public void ReadGroup03()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void ReadGroup03()
		{
			PasswordCryptoModule pwd = new PasswordCryptoModule("lkjlkjwijoiu");
			using (eWalletDataSet ds = new eWalletDataSet())
			{
				var key = ds.Groups.AddGroupsRow("Default", null, pwd);
				Guid id = key.Id;
				Assert.AreNotEqual<Guid>(Guid.Empty, id);

				ds.Groups.AddGroupsRow("Not Default", null, pwd);

				using (BlobsTableAdapter adr = new BlobsTableAdapter(this.DatabasePath))
				{
					adr.Update(ds.Blobs);
				}
				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					int i = adr.Update(ds.Groups);
					Assert.AreEqual<int>(2, i);

					ds.Groups.Clear();
					Assert.AreEqual<int>(0, ds.Groups.Count);

					i = adr.Fill(ds.Groups, id);
					Assert.AreEqual<int>(1, i);
					Assert.AreEqual<Guid>(id, ds.Groups[0].Id);
				}
			}
		}

		#endregion

		#region Test: public void ReadGroup04()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void ReadGroup04()
		{
			PasswordCryptoModule mod = new PasswordCryptoModule("password");
			Guid id;
			using (eWalletDataSet ds = new eWalletDataSet())
			{
				var group = ds.Groups.AddGroupsRow("Default", null, mod);
				id = group.Id;

				using (BlobsTableAdapter adr = new BlobsTableAdapter(this.DatabasePath))
				{
					adr.Update(ds.Blobs);
				}
				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					adr.Update(ds.Groups);
				}

				using (SqlCeConnection conn = new SqlCeConnection(this.ConnectionString))
				{
					using (SqlCeCommand cmd = new SqlCeCommand("UPDATE [Groups] SET [EncryptionMethod] = 1 WHERE [Id] = @Id", conn))
					{
						cmd.Parameters.AddWithValue("@Id", id);
						conn.Open();
						int i = cmd.ExecuteNonQuery();
						Assert.AreEqual<int>(1, i);
					}
				}
			}

			using (eWalletDataSet ds = new eWalletDataSet())
			{
				using (GroupsTableAdapter adr = new GroupsTableAdapter(this.DatabasePath))
				{
					int i = adr.Fill(ds.Groups, id);
					Assert.AreEqual<int>(1, i);
				}

				Assert.AreEqual<int>(1, ds.Groups.Count);
				Assert.AreEqual<EncryptionMethod>(EncryptionMethod.Certificate, ds.Groups[0].EncryptionMethod);
			}

		}

		#endregion



		#region Test: public void SaveSecret01()

		[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute()]
		[global::Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute(" ")]
		public void SaveSecret01()
		{
			PasswordCryptoModule pwd = new PasswordCryptoModule("1234");

			using (TableAdapterManager tam = new TableAdapterManager(this.DatabasePath))
			{
				using (eWalletDataSet ds = new eWalletDataSet())
				{
					ds.Groups.AddGroupsRow("Default", null, pwd);

					var row = ds.Secrets.NewSecretsRow(Guid.NewGuid());
					row.GroupsRow = ds.Groups[0];
					row.ContentType = "text/plain";
					row.Description = "Description 1";
					row.SetFileNameNull();
					row.LastModified = DateTime.UtcNow;
					row.LastModifiedBy = "Admin";
					row.EncryptData("Very secret data", pwd);
					ds.Secrets.AddSecretsRow(row);

					tam.BlobsTableAdapter.Update(ds.Blobs);
					tam.GroupsTableAdapter.Update(ds.Groups);
					tam.SecretsTableAdapter.Update(ds.Secrets);
				}

				using(eWalletDataSet ds = new eWalletDataSet())
				{
					int i = tam.BlobsTableAdapter.Fill(ds.Blobs);
					Assert.AreEqual<int>(2, i);

					i = tam.SecretsTableAdapter.Fill(ds.Secrets);
					Assert.AreEqual<int>(1, i);
				}
			}
		}

		#endregion
		
	}
}
